import 'dart:math';

import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'package:flutter/services.dart' show rootBundle;
import 'dart:async';
import 'dart:typed_data';

class ImageShaderDemo extends StatefulWidget {
  @override
  _ImageShaderDemoState createState() => _ImageShaderDemoState();
}

class _ImageShaderDemoState extends State<ImageShaderDemo>
    with SingleTickerProviderStateMixin {
  late ui.Image fillImage;
  bool isImageLoaded = false;
  late Animation<double> animation;
  late AnimationController controller;

  void initState() {
    super.initState();
    init();
  }

  Future<Null> init() async {
    final ByteData data = await rootBundle.load('images/earth.jpeg');
    fillImage = await loadImage(Uint8List.view(data.buffer));
    controller =
        AnimationController(duration: const Duration(seconds: 20), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
      parent: controller,
      curve: Curves.linear,
    ))
      ..addListener(() {
        setState(() {});
      });
    controller.repeat();
  }

  Future<ui.Image> loadImage(Uint8List img) async {
    final Completer<ui.Image> completer = Completer();
    ui.decodeImageFromList(img, (ui.Image img) {
      setState(() {
        isImageLoaded = true;
      });
      return completer.complete(img);
    });
    return completer.future;
  }

//Display image
  Widget _buildImage() {
    if (this.isImageLoaded) {
      return CustomPaint(
        painter: ImageEditor(
          image: fillImage,
          animationValue: animation.value,
        ),
      );
    } else {
      return Center(
        child: CircularProgressIndicator(),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: _buildImage(),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

class ImageEditor extends CustomPainter {
  ui.Image image;
  double animationValue;
  ImageEditor({required this.image, required this.animationValue});

  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint();
    paint.style = PaintingStyle.fill;
    paint.shader = ImageShader(
      image,
      TileMode.repeated,
      TileMode.mirror,
      (Matrix4.identity()
            ..translate(5 * animationValue, 5 * animationValue)
            ..scaled(2)
            ..rotateZ(2 * pi * animationValue))
          .storage,
      filterQuality: FilterQuality.high,
    );
    Offset center = Offset(size.width / 2, size.height / 2);
    canvas.drawCircle(center, 200, paint);

    // paint.shader = ImageShader(
    //   image,
    //   TileMode.mirror,
    //   TileMode.repeated,
    //   Matrix4.identity().storage,
    //   filterQuality: FilterQuality.high,
    // );
    // canvas.drawRect(Rect.fromLTRB(0, 0, size.width, size.height), paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
